#include "Url.hpp"

ZEND_BEGIN_ARG_INFO_EX(arginfo_registry_get, 0, 0, 1)
	ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_registry_set, 0, 0, 2)
	ZEND_ARG_INFO(0, key)
	ZEND_ARG_INFO(0, value)
	ZEND_ARG_INFO(0, overwrite)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_registry_delete, 0, 0, 1)
	ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()

static zend_function_entry php_registry_methods[] = {
	PHP_ME(Registry, get,    arginfo_registry_get,    ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_ME(Registry, set,    arginfo_registry_set,    ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_ME(Registry, delete, arginfo_registry_delete, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_FE_END
}; 

static inline void init_class_registry() {
	zend_class_entry ce; 
	
	// Evilworlds.Registry
	INIT_CLASS_ENTRY(ce, REGISTRY_CLASS_NAME, php_registry_methods); 
	php_registry_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); 
	memcpy(&php_registry_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 
	php_registry_object_handlers.clone_obj = NULL; 
	php_registry_ce -> ce_flags |= ZEND_ACC_FINAL_CLASS; 
	
	zend_declare_property_null(php_registry_ce, const_str_length("pool"), ZEND_ACC_STATIC | ZEND_ACC_PUBLIC TSRMLS_CC); 
	
}

static inline void destroy_class_registry() {
	
}

PHP_METHOD(Registry, get) {
	zval *pool, **retval; 
	char *key; int key_len; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &key, &key_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	pool = zend_read_static_property(php_registry_ce, const_str_length("pool"), false TSRMLS_CC); 
	if (pool && Z_TYPE_P(pool) == IS_ARRAY) {
		if (zend_hash_find(Z_ARRVAL_P(pool), key, key_len + 1, (void **)&retval) == SUCCESS)
			RETURN_ZVAL(*retval, true, false); 
	}
	RETURN_NULL(); 
}

PHP_METHOD(Registry, set) {
	zval *pool, *value; 
	char *key; int key_len; zend_bool overwrite = false; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &key, &key_len, &value, &overwrite) != SUCCESS)
		WRONG_PARAM_COUNT; 
	pool = zend_read_static_property(php_registry_ce, const_str_length("pool"), false TSRMLS_CC); 
	if (pool) {
		if (Z_TYPE_P(pool) != IS_ARRAY)
			array_init(pool); 
		ulong h = zend_hash_func(key, key_len + 1); 
		if (zend_hash_quick_exists(Z_ARRVAL_P(pool), key, key_len + 1, h)) {
			if (overwrite) {
				Z_ADDREF_P(value); 
				zend_hash_quick_update(Z_ARRVAL_P(pool), key, key_len + 1, h, &value, sizeof(zval *), NULL); 
			} else {
				php_error(E_WARNING, "Attempt to overwrite exists key '%s' in registry!", key); 
				RETURN_FALSE; 
			}
		} else {
			Z_ADDREF_P(value); 
			zend_hash_quick_add(Z_ARRVAL_P(pool), key, key_len + 1, h, &value, sizeof(zval *), NULL); 
		}
		RETURN_TRUE; 
	}
}

PHP_METHOD(Registry, delete) {
	zval *pool; 
	char *key; int key_len; 
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &key, &key_len) != SUCCESS)
		WRONG_PARAM_COUNT; 
	
	pool = zend_read_static_property(php_registry_ce, const_str_length("pool"), false TSRMLS_CC); 
	if (pool && Z_TYPE_P(pool) == IS_ARRAY) {
		if (zend_hash_del(Z_ARRVAL_P(pool), key, key_len + 1) == SUCCESS)
			RETURN_TRUE; 
	}
	RETURN_FALSE; 
}
